/*
	* Created by : Varun Tyagi
	*
	* This tutorial covers mouse event handling.
*/

/* Header files. */
#include "SDL.h"
#include "SDL_image.h"
#include <string>

/* Screen attributes. */
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

/* The button state in the sprite sheet. */
const int CLIP_MOUSEOVER = 0;
const int CLIP_MOUSEOUT = 1;
const int CLIP_MOUSEDOWN = 2;
const int CLIP_MOUSEUP = 3;

/* The surface. */
SDL_Surface *pButtonSheet = nullptr;
SDL_Surface *pScreen  = nullptr;

/* The event structure. */
SDL_Event event;

/* The clip region for sprite sheet. */
SDL_Rect clips[4];

/* Button Class. */
class Button
{
private:

	/* Attributes of the button. */
	SDL_Rect box;

	/* The part of the button sprite sheet that will be shown. */
	SDL_Rect *pClip;

public:

	/* Constructor. */
	Button( int x, int y, int w, int h );

	/* Handle the events and set the buttons sprite region. */
	void handle_events( void );

	/* Shows the button on the screen. */
	void show( void );
};

/* Image loader. */
SDL_Surface *load_image( std::string filename )
{
	/* The image that is loaded. */
	SDL_Surface *pLoadedImage;

	/* The optimized version of the loaded image. */
	SDL_Surface *pOptimizedImage; 

	/* Load the image. */
	pLoadedImage = IMG_Load( filename.c_str() );

	/* Check to see if the image has been correctly loaded. */
	if( nullptr != pLoadedImage )
	{
		/* Create an optimized image. */
		pOptimizedImage = SDL_DisplayFormat( pLoadedImage );

		/* Free the old image. */
		SDL_FreeSurface( pLoadedImage );

		/* If the surface is optimized. */
		if( nullptr != pOptimizedImage )
		{
			/* Color key surface. */
			SDL_SetColorKey( pOptimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( pOptimizedImage->format, 0, 0xFF, 0xFF ) );
		}
	}

	/* Return the optimized image. */
	return pOptimizedImage;
}

/* Apply surface. */
void apply_surface( int x, int y, SDL_Surface *pSource, SDL_Surface *pDestination, SDL_Rect *pClip = nullptr )
{
	/* Holds the offset. */
	SDL_Rect offset;

	/* Get offsets. */
	offset.x = x;
	offset.y = y;

	/* Blit the surface. */
	SDL_BlitSurface( pSource, pClip, pDestination, &offset );
}

/* Initialize SDL. */
bool init_SDL( void )
{
	/* Initialize all SDL subsystems. */
	if( -1 == SDL_Init( SDL_INIT_EVERYTHING ) )
	{
		return false;
	}

	/* Set up the screen. */
	pScreen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );

	/* Check the loaded screen. */
	if( nullptr == pScreen )
	{
		return false;
	}

	/* Set the window caption. */
	SDL_WM_SetCaption( "Mouse Handler", nullptr );

	/* Return. */
	return true;
}

/* File loader. */
bool load_file( void )
{
	/* Load the button sprite sheet. */
	pButtonSheet = load_image( "button.png" );

	/* Check the loaded sheet. */
	if( nullptr == pButtonSheet )
	{
		return false;
	}

	/* Return. */
	return true;
}

/* Clean up SDL. */
void clean_SDL( void )
{
	/* Free surface. */
	SDL_FreeSurface( pButtonSheet );

	/* QUIT. */
	SDL_Quit();
}

/* Set window clips. */
void set_clips( void )
{
	/* Clip the sprite sheet. */
	clips[ CLIP_MOUSEOVER ].x = 0;
	clips[ CLIP_MOUSEOVER ].y = 0;
	clips[ CLIP_MOUSEOVER ].w = 320;
	clips[ CLIP_MOUSEOVER ].h = 240;

	clips[ CLIP_MOUSEOUT ].x = 320;
	clips[ CLIP_MOUSEOUT ].y = 0;
	clips[ CLIP_MOUSEOUT ].w = 320;
	clips[ CLIP_MOUSEOUT ].h = 240;

	clips[ CLIP_MOUSEDOWN ].x = 0;
	clips[ CLIP_MOUSEDOWN ].y = 240;
	clips[ CLIP_MOUSEDOWN ].w = 320;
	clips[ CLIP_MOUSEDOWN ].h = 240;

	clips[ CLIP_MOUSEUP ].x = 320;
	clips[ CLIP_MOUSEUP ].y = 240;
	clips[ CLIP_MOUSEUP ].w = 320;
	clips[ CLIP_MOUSEUP ].h = 240;
}

/* Button class. */
Button::Button( int x, int y, int w, int h )
{
	box.x = x;
	box.y = y;
	box.w = w;
	box.h = h;

	/* set the default clip sprite. */
	pClip = &clips[ CLIP_MOUSEOUT ];
}

void Button::handle_events( void )
{
	/* The mouse offset. */
	int x = 0;
	int y = 0;

	/* If the mouse moved. */
	if( SDL_MOUSEMOTION == event.type )
	{
		/* Get the mouse offset. */
		x = event.motion.x;
		y = event.motion.y;

		/* If the mouse is over a button. */
		if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
		{
			/* Set the button sprite. */
			pClip = &clips[ CLIP_MOUSEOVER ];
		}

		/* if not. */
		else
		{
			/* Set the button sprite. */
			pClip = &clips[ CLIP_MOUSEOUT ];
		}
	}

	/* If the mouse button was pressed. */
	if( SDL_MOUSEBUTTONDOWN == event.type )
	{
		/* If the left mouse button was pressed. */
		if( SDL_BUTTON_LEFT == event.button.button )
		{
			/* Get the mouse offset. */
			x = event.button.x;
			y = event.button.y;

			/* Check to see if the mouse is over a button. */
			if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
			{
				/* Clips the sprite buttons. */
				pClip = &clips[ CLIP_MOUSEDOWN ];
			}
		}
	}

	/* If the mouse button was released. */
	if( SDL_MOUSEBUTTONUP == event.type )
	{
		/* If the left mouse button was released. */
		if( SDL_BUTTON_LEFT == event.button.button )
		{
			/* Get the mouse offset. */
			x = event.button.x;
			y = event.button.y;

			/* Check to see if the mouse is over a button. */
			if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
			{
				/* Clips the sprite buttons. */
				pClip = &clips[ CLIP_MOUSEUP ];
			}
		}
	}

}

/* Show the mouse. */
void Button::show( void )
{
	/* Show the button. */
	apply_surface( box.x, box.y, pButtonSheet, pScreen, pClip );
}

/* Main. */
int main( int argc, char** argv )
{
	/* QUIT. */
	bool bQuit = false;

	/* Initialize. */
	if( false == init_SDL() )
	{
		return 1;
	}

	/* Load the files. */
	if( load_file() == false )
	{
		return 1;
	}

	//Clip the sprite sheet
	set_clips();

	//Make the button
	Button myButton( 170, 120, 320, 240 );

	//While the user hasn't quit
	while( bQuit == false )
	{
		//If there's events to handle
		if( SDL_PollEvent( &event ) )
		{
			//Handle button events
			myButton.handle_events();

			//If the user has Xed out the window
			if( event.type == SDL_QUIT )
			{
				//Quit the program
				bQuit = true;
			}
		}

		//Fill the screen white
		SDL_FillRect( pScreen, &pScreen->clip_rect, SDL_MapRGB( pScreen->format, 0xFF, 0xFF, 0xFF ) );

		//Show the button
		myButton.show();

		//Update the screen
		if( SDL_Flip( pScreen ) == -1 )
		{
			return 1;
		}
	}

	//Clean up
	clean_SDL();

	return 0;
}

